#include "porting.h"

static bool os_mutex_init(struct qmutex_t *qmutex);
static void os_mutex_destroy(struct qmutex_t *qmutex);
static bool os_mutex_lock(struct qmutex_t *qmutex);
static void os_mutex_unlock(struct qmutex_t *qmutex);

static bool os_sem_init(struct qsem_t *qsem);
static void os_sem_destroy(struct qsem_t *qsem);
static bool os_sem_wait(struct qsem_t *qsem);
static void os_sem_post(struct qsem_t *qsem);

//porting header
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <semaphore.h>
#include <errno.h>

bool os_mutex_init(struct qmutex_t *qmutex)
{
    pthread_mutex_t *mutex;

    mutex = (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t));
    if(!mutex)
    {
        return false;
    }
    qmutex->private = mutex;

    pthread_mutex_init(qmutex->private,NULL);

    return true;
}

void os_mutex_destroy(struct qmutex_t *qmutex)
{
    if(!qmutex->private) { return ; }

    pthread_mutex_destroy(qmutex->private);

    free(qmutex->private);
    qmutex->private = NULL;
}

bool os_mutex_lock(struct qmutex_t *qmutex)
{
    if(!qmutex->private) { return false; }

    if(0 == pthread_mutex_lock(qmutex->private))
	{
		return true;
	}

	return false;
}

void os_mutex_unlock(struct qmutex_t *qmutex)
{
    if(!qmutex->private) { return ; }
    
    pthread_mutex_unlock(qmutex->private);
}

bool os_sem_init(struct qsem_t *qsem)
{
    sem_t *sem;

    sem = (sem_t *)malloc(sizeof(sem_t));
    if(!sem)
    {
        return false;
    }
    qsem->private = sem;

    if(0 == sem_init(qsem->private,0,0))
    {
        return true;
    }

    return false;
}

void os_sem_destroy(struct qsem_t *qsem)
{
    if(!qsem->private) { return ; }
    
    sem_destroy(qsem->private);

    free(qsem->private);
    qsem->private = NULL;
}

bool os_sem_wait(struct qsem_t *qsem)
{
    if(!qsem->private) { return false; }

    do {
		if(0 != sem_wait(qsem->private))
		{
			if((errno == EINTR) || (errno == EAGAIN))
			{
				continue;
			}
			else
			{
				return false;
			}
		}
		break;
	}while(1);

	return true;
}

void os_sem_post(struct qsem_t *qsem)
{
    if(!qsem->private) { return ; }
    
    sem_post(qsem->private);
}

bool porting_init(struct qmutex_t **qmutex, struct qsem_t **qsem)
{
    struct qmutex_t *mutex;
    struct qsem_t *sem;

    if(qmutex)
    {
        mutex = (struct qmutex_t *)malloc(sizeof(struct qmutex_t));
        if(!mutex)
        {
            return false;
        }
        mutex->init = os_mutex_init;
        if(true != mutex->init(mutex))
        {
            return false;
        }
        mutex->destroy = os_mutex_destroy;
        mutex->lock = os_mutex_lock;
        mutex->unlock = os_mutex_unlock;

        *qmutex = mutex;
    }

    if(qsem)
    {
        sem = (struct qsem_t *)malloc(sizeof(struct qsem_t));
        if(!sem)
        {
            return false;
        }
        sem->init = os_sem_init;
        if(true != sem->init(sem))
        {
            mutex->destroy(mutex);
            free(mutex);

            return false;
        }
        sem->destroy = os_sem_destroy;
        sem->wait = os_sem_wait;
        sem->post = os_sem_post;
        
        *qsem = sem;
    }

    return true;
}

void porting_destroy(struct qmutex_t *qmutex, struct qsem_t *qsem)
{
    if(qmutex)
    {
        qmutex->destroy(qmutex);
        free(qmutex);
    }
    
    if(qsem)
    {
        qsem->destroy(qsem);
        free(qsem);
    }
}
